﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace alphabook
{
    class Book 
    {
        private int id = -1;
        public int ID
        {
            get { return id; }
        }

        private bool deleted = false;
        public Boolean Deleted
        {
            get { return deleted; }
        }

        private string title;
        public String Title {
            get { return title; }
            set { title = value; Update(); }
        }

        private int year = -1;
        public int Year
        {
            get { return year; }
            set { year = value; Update(); }
        }

        private string author;
        public String Author
        {
            get { return author; }
            set { author = value; Update(); }
        }

        /// <summary>
        /// Creates an empty book
        /// </summary>
        public Book()
        {
        }

        /// <summary>
        /// Creates an book
        /// </summary>
        /// <param name="title">Title</param>
        /// <param name="year">Year</param>
        /// <param name="author">Full name of author</param>
        public Book(String title, int year, String author)
        {
            this.title = title;
            this.year = year;
            this.author = author;
            this.Insert();
        }

        /// <summary>
        /// Creates an book without year
        /// </summary>
        /// <param name="title">Title</param>
        /// <param name="author">Full name of author</param>
        public Book(String title, String author)
        {
            this.title = title;
            this.author = author;
            this.Insert();
        }

        /// <summary>
        /// Creates an existing book with id, used for fetching
        /// </summary>
        /// <param name="id">Book ID</param>
        /// <param name="title">Title</param>
        /// <param name="year">Year</param>
        /// <param name="author">Full name of author</param>
        public Book(int id, String title, int year, String author)
        {
            this.id = id;
            this.title = title;
            this.year = year;
            this.author = author;
        }

        /// <summary>
        /// Deletes the book by ID
        /// </summary>
        /// <returns>0 - success, 1 - other error </returns>
        public bool Delete()
        {
            Database db = new Database();
            if (this.id == -1)
            {
                return false;
            }
            int rows = db.Execute("UPDATE BOOK SET deleted = 1 WHERE book_ID = " + this.id);
            db.Close();
            if (Util.checkResult(rows) == 0)
            {
                this.deleted = true;
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Update book values
        /// </summary>
        /// <returns>0 - success, 1 - failed</returns>
        private int Update()
        {
            Database db = new Database();
            if (this.id == -1)
            {
                return 0;
            }
            String sql = "UPDATE BOOK SET title = '" + this.title +
            "', year = " + this.year + ", author = '" + this.author +
            "', deleted = 0 WHERE book_ID = " + this.id;
            int rows = db.Execute(sql);
            db.Close();
            return Util.checkResult(rows);

        }

        /// <summary>
        /// Saves the book to database
        /// </summary>
        /// <returns>0 - success, -1 - book exists, 1 - other error</returns>
        private int Insert()
        {
            Database db = new Database();
            ArrayList check = db.Query("SELECT * FROM BOOK WHERE title = '" + this.title + "';");
            if (check.Count == 0)
            {

                int rows = db.Execute("INSERT INTO BOOK VALUES(null, '" + this.title + "', " +
                    ((this.year != -1)? this.year + ", '": ", '")  + this.author + "', 0);");
                ArrayList id = db.Query("SELECT * FROM BOOK WHERE title = '" + this.title + "';");
                Dictionary<String, object> d = (Dictionary<String, object>)id[0];
                this.id = (int)d["book_ID"];
                db.Close();
                return Util.checkResult(rows);
            }
            else
            {
                this.title = "";
                db.Close();
                return -1;
            }
        }

        /// <summary>
        /// Fetch all books
        /// </summary>
        /// <returns>Array of Books</returns>
        public static Book[] getAllBooks()
        {
            Database db = new Database();
            ArrayList result = db.Query("SELECT * FROM BOOK;");
            db.Close();
            Book[] books = new Book[result.Count];
            for (int i = 0; i < result.Count; i++)
            {
                Dictionary<String, object> d = (Dictionary<string, object>)result[i];
                books[i] = new Book((int)d["book_ID"], (String)d["title"], (int)d["year"], (String)d["author"]);
            }
            return books;
        }

        /// <summary>
        /// Fetch present books
        /// </summary>
        /// <returns>Array of Books</returns>
        public static Book[] getPresentBooks()
        {
            Database db = new Database();
            Loan[] loans = Loan.GetActiveLoans();
            ArrayList result = db.Query("SELECT * FROM BOOK;");
            db.Close();


            ArrayList books = new ArrayList();
            ArrayList filteredBooks = new ArrayList();
            for (int i = 0; i < result.Count; i++)
            {
                Dictionary<String, object> d = (Dictionary<string, object>)result[i];
                books.Add(new Book((int)d["book_ID"], (String)d["title"], (int)d["year"], (String)d["author"]));
            }
            foreach(Book b in books) {
                if (loans.Length == 0)
                {
                    filteredBooks.Add(b);
                    continue;
                }
                foreach(Loan l in loans) {
                    if (b.ID != l.LentBook.ID)
                    {
                        filteredBooks.Add(b);
                        break;
                    }

                }
            }
            return (Book[])filteredBooks.ToArray(typeof(Book));
        }


        /// <summary>
        /// Fetches book by title
        /// </summary>
        /// <param name="title">Title of book to be found</param>
        /// <returns>Found Book</returns>
        public static Book getBook(String title)
        {
            Database db = new Database();
            ArrayList result = db.Query("SELECT * FROM BOOK WHERE title = '" + title + "';");
            db.Close();
            if (result.Count != 0)
            {
                Dictionary<String, object> d = (Dictionary<string, object>)result[0];
                return new Book((int)d["book_ID"], (String)d["title"], (int)d["year"], (String)d["author"]);
            }
            else
            {
                return new Book();
            }
        }

        /// <summary>
        /// Fetches book by id
        /// </summary>
        /// <param name="id">ID of book to be found</param>
        /// <returns>Found Book</returns>
        public static Book getBook(int id)
        {
            Database db = new Database();
            ArrayList result = db.Query("SELECT * FROM BOOK WHERE book_ID = '" + id + "';");
            db.Close();
            if (result.Count != 0)
            {
                Dictionary<String, object> d = (Dictionary<string, object>)result[0];
                return new Book(id, (String)d["title"], (int)d["year"], (String)d["author"]);
            }
            else
            {
                return new Book();
            }
        }
    }
}
